/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.lvyh.lightframe.sharding.client.util;


import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public final class ReflectionUtil {

    private ReflectionUtil() {
    }

    public static Field getField(Object obj, String name) {
        Field field = ReflectionUtils.findField(obj.getClass(), name);
        field.setAccessible(true);
        return field;
    }

    public static void setField(Object obj, String target, String value) throws IllegalAccessException {
        Field field = getField(obj, target);
        field.set(obj, value);
    }

    public static void setField(Object obj, String target, Object value) throws IllegalAccessException {
        Field field = getField(obj, target);
        field.set(obj, value);
    }

    public static Object getFieldValue(Object object, String key) throws IllegalAccessException {
        if (object instanceof Map) {
            Object o = ((Map) object).get(key);
            if (o != null) {
                return o;
            } else {
                Object sharding = ((Map) object).get("sharding");
                return getFieldValue(sharding, key);
            }
        } else if (object instanceof Long) {
            return object.toString();
        }
        Class<?> clazz = object.getClass();
        Field[] fields = clazz.getDeclaredFields();
        for (Field f : fields) {
            f.setAccessible(true);
            if (f.getName().equals(key)) {
                return f.get(object);
            }
        }
        return null;
    }

    public static Object getFieldValue(Object object, String key, boolean containSuperClass) throws IllegalAccessException {
        Class<?> clazz = object.getClass();
        List fieldsList = new ArrayList<Field[]>();
        while (clazz != null) {  // Traverse all parent bytecode objects
            Field[] declaredFields = clazz.getDeclaredFields();  // Gets the property object array of the bytecode object
            fieldsList.add(declaredFields);

            clazz = clazz.getSuperclass();  // Gets the bytecode object of the parent class
        }

        for (Object fields : fieldsList) {
            Field[] f = (Field[]) fields;
            for (Field field : f) {
                field.setAccessible(true);
                if (field.getName().equals(key)) {
                    return field.get(object);
                }
            }
        }

        return null;
    }

    public static Byte parseByte(String value) {
        try {
            value = value.replaceAll("　", "");
            return Byte.valueOf(value);
        } catch (NumberFormatException e) {
            throw new RuntimeException("parseByte but input illegal input=" + value, e);
        }
    }

    public static Boolean parseBoolean(String value) {
        value = value.replaceAll("　", "");
        if (Boolean.TRUE.toString().equalsIgnoreCase(value)) {
            return Boolean.TRUE;
        } else if (Boolean.FALSE.toString().equalsIgnoreCase(value)) {
            return Boolean.FALSE;
        } else {
            throw new RuntimeException("parseBoolean but input illegal input=" + value);
        }
    }

    public static Integer parseInt(String value) {
        try {
            value = value.replaceAll("　", "");
            return Integer.valueOf(value);
        } catch (NumberFormatException e) {
            throw new RuntimeException("parseInt but input illegal input=" + value, e);
        }
    }

    public static Short parseShort(String value) {
        try {
            value = value.replaceAll("　", "");
            return Short.valueOf(value);
        } catch (NumberFormatException e) {
            throw new RuntimeException("parseShort but input illegal input=" + value, e);
        }
    }

    public static Long parseLong(String value) {
        try {
            value = value.replaceAll("　", "");
            return Long.valueOf(value);
        } catch (NumberFormatException e) {
            throw new RuntimeException("parseLong but input illegal input=" + value, e);
        }
    }

    public static Float parseFloat(String value) {
        try {
            value = value.replaceAll("　", "");
            return Float.valueOf(value);
        } catch (NumberFormatException e) {
            throw new RuntimeException("parseFloat but input illegal input=" + value, e);
        }
    }

    public static Double parseDouble(String value) {
        try {
            value = value.replaceAll("　", "");
            return Double.valueOf(value);
        } catch (NumberFormatException e) {
            throw new RuntimeException("parseDouble but input illegal input=" + value, e);
        }
    }


    /**
     * Parameter parsing（support：Byte、Boolean、String、Short、Integer、Long、Float、Double、Date）
     *
     * @param fieldType
     * @param value
     * @return
     */
    public static Object parseValue(Class<?> fieldType, String value) {
        // Class<?> fieldType = field.getType();	// Field field

        if (value == null || value.trim().length() == 0)
            return null;
        value = value.trim();

        if (String.class.equals(fieldType)) {
            return value;
        } else if (Boolean.class.equals(fieldType) || Boolean.TYPE.equals(fieldType)) {
            return parseBoolean(value);
        } /*else if (Byte.class.equals(fieldType) || Byte.TYPE.equals(fieldType)) {
            return parseByte(value);
		}  else if (Character.class.equals(fieldType) || Character.TYPE.equals(fieldType)) {
			 return value.toCharArray()[0];
		}*/ else if (Short.class.equals(fieldType) || Short.TYPE.equals(fieldType)) {
            return parseShort(value);
        } else if (Integer.class.equals(fieldType) || Integer.TYPE.equals(fieldType)) {
            return parseInt(value);
        } else if (Long.class.equals(fieldType) || Long.TYPE.equals(fieldType)) {
            return parseLong(value);
        } else if (Float.class.equals(fieldType) || Float.TYPE.equals(fieldType)) {
            return parseFloat(value);
        } else if (Double.class.equals(fieldType) || Double.TYPE.equals(fieldType)) {
            return parseDouble(value);
        } else {
            throw new RuntimeException("illeagal conf data type, type=" + fieldType);
        }
    }

}